package middleware

import (
	"errors"
	"gin_vue_blog/utils"
	"gin_vue_blog/utils/errmsg"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v4"
	"strings"
)

// JWT结构体
type JWT struct {
	JWTKey []byte // JWT密钥
}

func NewJWT() *JWT { //新建JWT结构体
	return &JWT{
		JWTKey: []byte(utils.Config_Message.Server.JWTKey),
	}
}

// 自定义声明
type MyClaims struct {
	Username string `json:"username"` //这里的与gorm中声明的保持一致
	jwt.RegisteredClaims
}

// 定义相关错误信息
var (
	TokenExpired     error = errors.New("token已过期，请重新登录")
	TokenNotValidYet error = errors.New("token无效，请重新登录")
	TokenMalformed   error = errors.New("token不正确，请重新登录")
	TokenInvalid     error = errors.New("这不是一个token，请重新登录")
)

// 生成token
func (j *JWT) CreateToken(claims MyClaims) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(j.JWTKey)
}

// 解析token

func (j *JWT) ParseToken(tokenString string) error {
	// 解析token
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return j.JWTKey, nil
	})

	// 校验token
	if token.Valid {
		return nil
	} else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) {
		return TokenExpired
	} else if errors.Is(err, jwt.ErrSignatureInvalid) {
		return TokenInvalid
	} else if errors.Is(err, jwt.ErrTokenMalformed) {
		return TokenMalformed
	} else {
		return TokenNotValidYet
	}
}

//jwt中间件

func JwtToken() gin.HandlerFunc {
	return func(c *gin.Context) {
		var code int
		//检验Header
		tokenHeader := c.Request.Header.Get("Authorization")
		if tokenHeader == "" {
			code = errmsg.ERROR_TOKEN_NOT_EXIST
			c.JSON(200, gin.H{
				"status":  code,
				"message": errmsg.GetErrMsg(code),
			})
			c.Abort() //拦截中间件
		}
		checkToken := strings.Split(tokenHeader, " ")
		if len(checkToken) == 0 {
			code = errmsg.ERROR_TOKEN_TYPE_WRONG
			c.JSON(200, gin.H{
				"status":  code,
				"message": errmsg.GetErrMsg(code),
			})
			c.Abort()
			return
		}

		if len(checkToken) != 2 || checkToken[0] != "Bearer" {
			c.JSON(200, gin.H{
				"status":  code,
				"message": errmsg.GetErrMsg(code),
			})
			c.Abort()
			return
		}
		//解析token
		j := NewJWT()
		err := j.ParseToken(checkToken[1])
		if err != nil {
			if errors.Is(err, TokenExpired) {
				c.JSON(200, gin.H{
					"status":  errmsg.ERROR_TOKEN_RUNTIME,
					"message": errmsg.GetErrMsg(errmsg.ERROR_TOKEN_RUNTIME),
				})
				c.Abort()
				return
			} else {
				c.JSON(200, gin.H{
					"status":  errmsg.ERROR,
					"message": err.Error(),
				})
				c.Abort()
				return
			}
		}
		c.Next()
		return
	}
}
